using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;

namespace SymbolicComputation
{
    public class TransformBranchFunctions
    {
        public static String[] Combinatorize(String equation,String[] transformStrings,out ArtificialIntelligence.AI ai)
        {
            if (equation == "" | equation == null)
            {
                ai = null;
                return null;
            }
            SymbolicComputation.AI.SolveEquationBase worker = new SymbolicComputation.AI.SolveEquationBase();
            worker.Transforms = Transform.StringToTransforms(transformStrings.ToArray()).ToList();
            String result = worker.Solve(equation);
            String[] results = ArtificialIntelligence.Job.Equations(worker.ai.jobStates.ToArray());
            ai = worker.ai;
            return results;
        }

        public static List<String> TransformBranchesWithTransform(String transformMe, String transformString, ref List<AI.HistoricalMoment> historicalMoments)
        {
            Transform transform = Transform.StringToTransform(transformString);
            SyntaxNode transformMeAsTree = Miscellaneous.EquationToSyntaxNode(transformMe);
            List<SyntaxNode> results = TransformBranchesWithTransform(transformMeAsTree, transform, ref historicalMoments);
            return Miscellaneous.SyntaxNodesToStrings(results.ToArray()).ToList();
        }

        public static List<SyntaxNode> TransformBranchesWithTransform(SyntaxNode root, Transform transform, ref List<AI.HistoricalMoment> historicalMoments)
        {
            return TransformBranchesWithTransforms(root, Functional.Maps.Map(transform).ToList(),ref historicalMoments);
        }

        public static List<String> TransformBranchesWithTransforms(String root, List<String> transforms,ref List<AI.HistoricalMoment> historicalMoments)
        {
            SyntaxNode rootAsTree = Miscellaneous.EquationToSyntaxNode(root);
            List<Transform> transformsAsTrees = Transform.StringToTransforms(transforms.ToArray()).ToList();
            List<SyntaxNode> results = TransformBranchesWithTransforms(rootAsTree, transformsAsTrees, ref historicalMoments);
            return Miscellaneous.SyntaxNodesToStrings(results.ToArray()).ToList();
        }

        public static List<SyntaxNode> TransformBranchesWithTransforms(SyntaxNode root, List<Transform> transforms, ref List<AI.HistoricalMoment> historicalMoments)
        {
            //this function is inefficient but the AI can study what types of branches can be transformed with what types of transforms
            Int32 branchIndex;
            List<SyntaxNode> lOut = new List<SyntaxNode>();
            int branchCount = root.DescendentNodesAndSelf().ToList().Count;
            List<SyntaxNode> tempNodes;
            for (branchIndex = 0; branchIndex < branchCount; branchIndex++)
            {
                tempNodes = TransformBranchWithTransforms(root, transforms, branchIndex, ref historicalMoments);
                lOut.AddRange(tempNodes);
            }
            return lOut;
        }

        public static List<SyntaxNode> TransformBranchesWithTransforms(SyntaxNode root, Dictionary<SyntaxKind,List<Transform>> inTransforms,ref List<AI.HistoricalMoment> historicalMoments)
        {
            Int32 branchIndex;
            List<SyntaxNode> lOut = new List<SyntaxNode>();
            List<SyntaxNode> branches=root.DescendentNodesAndSelf().ToList();
            int branchCount = branches.Count;
            List<SyntaxNode> tempNodes;
            List<Transform> transforms;
            for (branchIndex = 0; branchIndex < branchCount; branchIndex++)
            {
                if (inTransforms.ContainsKey(branches[branchIndex].Kind) == true)
                {
                    transforms = inTransforms[branches[branchIndex].Kind];
                    tempNodes = TransformBranchWithTransforms(root, transforms, branchIndex,ref historicalMoments);
                    lOut.AddRange(tempNodes);
                }
            }
            return lOut;
        }

        public static SyntaxNode TransformBranch(SyntaxNode rootClone, Transform transform,Int32 branchIndex)
        {
            SyntaxNode branch = Branch(rootClone, branchIndex);
            SyntaxNode transformedBranch = AlgebraTransform.TransformAlgebraicSyntaxNode(branch, transform.matchToMe, transform.outPattern);
            if (transformedBranch == null)
            {
                return null;
            }
            SyntaxNode parent = branch.Parent;
            transformedBranch = Transform.WrapNodeInBrackets(parent, transformedBranch);                           
            SyntaxNode lOut = rootClone.ReplaceNode(branch, transformedBranch);
            return lOut;
        }

        public static List<SyntaxNode> TransformBranchWithTransforms(SyntaxNode rootClone, List<Transform> transforms,Int32 branchIndex,ref List<AI.HistoricalMoment> historicalMoments)
        {
            Int32 transformIndex;
            SyntaxNode transformed;
            List<SyntaxNode> lOut = new List<SyntaxNode>();
            for (transformIndex = 0; transformIndex < transforms.Count; transformIndex++)
            {
                transformed = TransformBranch(rootClone, transforms[transformIndex],branchIndex);
                if (transformed != null)
                {
                    lOut.Add(transformed);
                    historicalMoments.Add(new AI.HistoricalMoment(transforms[transformIndex],branchIndex));
                }
            }
            return lOut;
        }

        public static SyntaxNode Branch(SyntaxNode root, Int32 branchIndex)
        {
            List<SyntaxNode> branches = root.DescendentNodesAndSelf().ToList();
            return branches[branchIndex];
        }
    }
}